#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <jsoncpp/json/json.h>
using namespace std;
#define SelfDefine 1
vector<string> enumToString = { "success", "divzero", "modezero", "unknow" };



const string ProtSep = " ";
const string LineBreakSep = "\r\n";
// 封装报文
string Encode(string& message) {
    int messagelen = message.size();
    return to_string(messagelen) + LineBreakSep + message + LineBreakSep;
}

bool Decode(string& package, string* message) {
    auto pos = package.find(LineBreakSep);
    if (pos == string::npos) {
        return false;
    }
    string lens = package.substr(0, pos);
    int messagelen = stoi(lens);
    int totallen = lens.size() + messagelen + 2 * LineBreakSep.size();
    if (package.size() < totallen) {
        return false; // 说明肯定不包含一个完整的报文
    }
    // 到此处，寿命肯定包含至少一个完整的报文
    *message = package.substr(pos + LineBreakSep.size(), totallen);
    package.erase(0, totallen);
    return true;
}

class Request {
public :
    Request() 
        :_x(0)
        ,_y(0)
        ,_op(0)
    {}
    Request(int x, int y, char op)
        :_x(x)
        ,_y(y)
        ,_op(op)
    {
    }

    string ToString() {
        return "[" + to_string(_x) + " " +  _op + " " +  to_string(_y) + "]";
    }
    void Inc() {
        _x++;
        _y++;
    }

    // 序列化
    string Serialize() {
    #ifdef SelfDefine 
        return to_string(_x) + ProtSep + _op + ProtSep + to_string(_y);
    #else 
        Json::Value root;
        root["_x"] = _x;
        root["_y"] = _y;
        root["_op"] = _op;
        Json::FastWriter writer;
        return writer.write(root);
    #endif
    }
    // 反序列化
    bool DeSerialize(const string& in) {
    #ifdef SelfDefine 
        auto left = in.find(ProtSep);
        auto right = in.rfind(ProtSep);
        if (left == string::npos || right == string::npos || left == right) {
            return false;
        }
        _x = stoi(in.substr(0, left));
        _y = stoi(in.substr(right + ProtSep.size()));
        string oper = in.substr(left + ProtSep.size(), right - (left + ProtSep.size()));
        if (oper.size() != 1) {
            return false;
        }
        _op = oper[0];
        return true;
    #else 
        Json::Value root;
        Json::Reader reader;
        bool res = reader.parse(in, root);
        if (res) {
            _x = root["_x"].asInt();
            _y = root["_y"].asInt();
            _op = root["_op"].asInt();
        }
        return res;
    #endif

    }

    int GetX() {
        return _x;
    }
    int GetY() {
        return _y;
    }
    char GetOp() {
        return _op;
    }
private :
    int _x;
    int _y;
    char _op;
};


class Response {
public :
    Response() 
        :_result(0)
        ,_code(0)
    {}
    Response(int result, int code) 
        :_result(result)
        ,_code(code)
    {
    }
    // 序列化
    string Serialize() {
    #ifdef SelfDefine 
        return to_string(_result) + ProtSep + to_string(_code);
    #else 
        Json::Value root;
        root["_result"] = _result;
        root["_code"] = _code;
        Json::FastWriter writer;
        return writer.write(root);
    #endif

    }
    // 反序列化
    bool DeSerialize(const string& in) {
    #ifdef SelfDefine 
        auto pos = in.find(ProtSep);
        if (pos == string::npos) {
            return false;
        }
        _result = stoi(in.substr(0, pos));
        _code = stoi(in.substr(pos + ProtSep.size()));
        return true;
    #else 
        Json::Value root;
        Json::Reader reader;
        bool res = reader.parse(in, root);
        if (res) {
            _result = root["_result"].asInt();
            _code = root["_code"].asInt();
        }
        return res;
    #endif

    }
    string ToString() {
        return to_string(_result) + " (" + enumToString[_code] + ")";
    }

    void SetResult(int result) {
        _result = result;
    }
    void SetCode(int code) {
        _code = code;
    }

private :
    int _result;
    int _code;
};



// 简单的工厂设计模式
class Factory {
    public :
    Factory() {

    }
    shared_ptr<Request> BuildRequest() {
        return shared_ptr<Request>(new Request());
    }
    shared_ptr<Request> BuildRequest(int x, int y, char op) {
        return shared_ptr<Request>(new Request(x, y, op));
    }

    shared_ptr<Response> BuildResponse() {
        return shared_ptr<Response>(new Response());
    }
    shared_ptr<Response> BuildResponse(int result, int code) {
        return shared_ptr<Response>(new Response(result, code));
    }
};